<?php
namespace Modules\Box\Entities;

// use Modules\Core\Entities\BaseEntity as Model;

// use Modules\Order\Traits\Skuable;
use Modules\Activity\Entities\BaseActivityModel;
use Modules\Box\Entities\BoxSku;

use \Modules\Box\Entities\BoxRecord;
use Modules\Category\Traits\Categoryable;
use ThrowException;

use Stats;


class Box extends BaseActivityModel
{
    // use Skuable;
    use Categoryable;
    
    protected $resourceType = 'boxes';
    static public $resourceName = '盒子';

    public $activityType = 'box';
    public $activityTypeText = '盲盒';

    protected $casts = [
        'detail_images' => 'array',
        'tags' => 'json',
        'order_reward' => 'json',
        'category_ids' => 'json',
        'invite_rule' => 'json'
    ];

    public function getType($type = 'node_type') 
    {
        $map = [
            'base_sku_type' => 'box',
            'node_type' => 'box'
        ];

        return @$map[$type];
    }

    public function getNodeEntity()
    {
        return $this;
    }

    public function scopeSearch($query, $key)
    {
        return $query->where('title', 'like', '%'.$key.'%');
    }

    // public function IP()
    // {
    //     return $this->belongsTo('\Modules\Category\Entities\Category', 'ip_id');
    // }

    public function image_tag()
    {
        return $this->belongsTo('\Modules\Category\Entities\ImageTag', 'image_tag_id');
    }

    public function skus()
    {
        return $this->hasMany('\Modules\Box\Entities\BoxSku', 'box_id');
    }

    public function normal_skus()
    {
    	return $this->skus()->type('normal');
    }

    public function hidden_skus()
    {
        return $this->skus()->type('hidden');
    }

    public function rooms()
    {
    	return $this->hasMany('\Modules\Box\Entities\BoxRoom', 'box_id');
    }

    public function onstock_rooms()
    {
        return $this->hasMany('\Modules\Box\Entities\BoxRoom', 'box_id')->where('status', 1);
    }

    // 绑定的抽奖
    public function lottery()
    {
    	return $this->belongsTo('\Modules\Activity\Entities\Lottery\Activity', 'lottery_id');
    }

    static public function beforeGetList($options)
    {
        if (@$options['IP'])
            $options['where']['ip_id'] = $options['IP'];

        if (@$options['tag'] == 'newest')
            $options['where']['is_recommend'] = 1;

        if (@$options['tag'] == 'recommend')
            $options['where']['is_newest'] = 1;

        if (isset($options['status'])) {
            $options['scopes']['status'] = $options['status'];
            // $options['where']['status'] = $options['status'];
        }

        return $options;
    }


    public function createSkus($total)
    {
    	$default = [
            'stock' => 10
    	];

    	$skus = [];

    	for ($i=0; $i < $total; $i++) { 
    		$default['uuid'] = uniqid();
    		array_push($skus, $default);
    	}

    	$this->normal_skus()->createMany($skus);

    	return [];
    }

    public function createRooms($total)
    {
        $skuStatus = [];

        // \Log::error('小盒数量: ' . $this->sku_total);

        for ($i=0; $i < $this->sku_total; $i++) {
            array_push($skuStatus, 0);
        }

    	$default = [
            'sku_total' => $this->sku_total,
            'sku_status' => $skuStatus
    	];

    	$rooms = [];

        $time = time();

    	for ($i=0; $i < $total; $i++) { 

    		$default['uuid'] = uniqid();
            $default['number'] = '1' . substr(strVal($time * 1000 + $i + 1), -11, 11);

            $ids = $this->normal_skus()->pluck('id')->all();
            shuffle($ids);

            // 如果 ids 不够数，则需要
            while (count($ids) < $this->sku_total) {
                array_push($ids, $ids[array_rand($ids)]);
            }

            $default['skus'] = $ids;

    		array_push($rooms, $default);
    	}

    	$this->rooms()->createMany($rooms);

    	return [];
    }

    public function randRoom($currentRoomId = 0)
    {
        $instance = $this->rooms()->where([
            ['id', '<>', $currentRoomId],
            'status' => 1
        ])->inRandomOrder()->first() ?: $this->rooms()->first();

        return $instance;
    }

    // 调整房间数量
    public function adjustRoom()
    {
        $diff = $this->room_total - $this->onstock_rooms()->count();

        // 不可创建超出30个的盒子
        if ($diff > 30) {
            $diff = 30;
        }

        // \Log::error('调整盒子:' . $diff);

        if ($diff > 0) {
            // 当前盒子少了，需要创建
            $this->createRooms($diff);
        }
        elseif ($diff < 0) {
            // 当前盒子多了，需要删除
            $diff = -1 * $diff;
            $this->onstock_rooms()->take($diff)->delete();
        }
    }

    // 重排所有房间
    public function resetAllRoom()
    {
        $this->rooms()->delete();
        $this->adjustRoom();
    }

    // 获取绑定的天猫上对应的开盒商品id
    // public function getTmailProductId()
    // {
    //     return $this->tmail_product_id ?: env('DEFAULT_TMAIL_PRODUCT_ID');
    // }

    // 连抽算法 (连续抽多个)抽开的sku。 返回sku列表
    // $wholdRoom 为true时为盒端模式
    public function randomSkus($total, $wholdRoom = false, $options = [])
    {
        // 有库存的普通款sku列表
        $skus = $this->normal_skus()->onStock()->where('stock', '>', 0)->get();

        // 库存不足
        if ($skus->sum('stock') < $total) {
            return false;
        }

        $start = $this->open_index + 1;
        $end = $start + $total - 1;

        // 计算是否可以出隐藏款 
        $hiddenSkuList = $this->hidden_skus()->where('probability', '>', 0)->where('stock', '>', 0)->onStock()->get();
        $hiddenSku = null;
        $hiddenSkuTotal = 0;
        $hiddenOpenIndex = 0;
        foreach ($hiddenSkuList as $item) {
            $hiddenOpenIndex = $item->canOpenHiddenSkuInRange($start, $end); 
            if ($hiddenOpenIndex) {
                $hiddenSku = $item;
                $hiddenSkuTotal = 1;
                break;
            }
        }

        $luckyList = [];
        $normalTotal = $total - $hiddenSkuTotal;

        // 端盒 + 1:1模式
        if ($wholdRoom && $this->sku_ratio_type === 1) {
            $list = $this->normal_skus()->where('stock', '>', 0)->take($normalTotal)->get();

            foreach ($list as $item) {
                array_push($luckyList, [
                    'skuable' => $item,
                    'total' => 1
                ]);
            }
        }
        elseif ($total === 1 && $this->sku_ratio_type === 1) {
            // 1:1模式，只选一个
            if ($normalTotal === 1) {
                $room = $this->rooms()->where('id', @$options['room_id'])->first();
                $sku = @$room->pickSku(intVal(@$options['sku_index']) - 1);
            
                $luckyList = [
                    [
                        'skuable' => $sku,
                        'total' => 1
                    ]
                ];
            }
        }
        elseif ($total === 1 && $this->sku_ratio_type != 1) {
            // 非1:1模式，只选一个
            if ($normalTotal === 1) {
                // $room = $this->rooms()->where('id', @$options['room_id'])->first();
                $sku = BoxSku::getEntity([
                    'id' => @$options['sku_id']
                ]);

                if (!$sku || $sku->stock <= 0) {
                    return false;
                }
                
                $luckyList = [
                    [
                        'skuable' => $sku,
                        'total' => 1
                    ]
                ];
            }
        }
        else {
           // 非1:1随便挑
           $luckyList = pickLuckySkuMaps($skus, 'odds', $normalTotal);
        }

        $takeIndex = $start;
        foreach ($luckyList as $key  => $item) {
            $temp = [];
            while (count($temp) < $item['total']) {
                // \Log::error($takeIndex);
                if ($takeIndex !== $hiddenOpenIndex) {
                    array_push($temp, $takeIndex);
                }
                $takeIndex ++;
            }

            $luckyList[$key]['skuable']->openIndex  = $temp[0];
            $luckyList[$key]['skuable']->openIndexs  = $temp;
        }

        if ($hiddenSku) {
            $hiddenSku->options = [
                'is_hidden_sku' => 1
            ];
            $hiddenSku->openIndex = $hiddenOpenIndex;
            $hiddenSku->openIndexs = [$hiddenOpenIndex];

            $openIndexArray = $hiddenSku->open_indexs ?: [];
            array_push($openIndexArray, $hiddenOpenIndex);
            $hiddenSku->open_indexs = $openIndexArray;

            $hiddenSkuMap = [
                'skuable' => $hiddenSku,
                'total'  => 1
            ];
            // \Log::error($luckyList);
            if ($luckyList && count($luckyList) > 0) {
                $luckyList = array_merge([$hiddenSkuMap], $luckyList);
            }
            else {
                $luckyList = [$hiddenSkuMap];
            }
        }

        return $luckyList;
    }

    // 整盒端抽出的所有sku，返回sku列表
    public function getWholdRoomSkus()
    {
        $total = $this->sku_total;

        // 端盒模式
        return $this->randomSkus($total, true);
    }

    // 
    public function updateSalesAndStock()
    {
        $this->update([
            // 'sales' => $this->skus()->sum('sales'),
            'stock' => $this->normal_skus()->sum('stock'),
        ]);
    }

    // 抽出幸运sku
    public function pickLuckySkus($total, $user = NULL, $order = NULL, $optoins = [])
    {
        // 是否整盒端
        $isWholeBox = @$order['options']['is_whole_box'];

        // 整盒端
        if ($isWholeBox) {
            $luckyList = $this->getWholdRoomSkus();
        }
        // elseif ($total === 1 && @$order->options['sku_id']) {
        //     $sku = $this->skus()->where('id', $order->options['sku_id'])->first();

        //     $luckyList = [
        //         [
        //             'skuable' => $sku,
        //             'total' => 1
        //         ]
        //     ];
        // }
        // elseif ($total === 1 && $this->sku_ratio_type === 1) {
        //     // 开一个，且不允许重复
        //     $room = $this->rooms()->where('id', @$order['options']['room_id'])->first();
        //     if (!$room) {
        //         \Log::error('房间不存在，盲盒订单' . $order->id . '无法开盒~');
        //     }
        //     $sku = $room->pickSku(@$order['options']['sku_index']);
            
        //     $luckyList = [
        //         [
        //             'skuable' => $sku,
        //             'total' => 1
        //         ]
        //     ];
        // }
        else {
            $luckyList = $this->randomSkus($total, false, $order->options);
        }

        // 扣除库存
        foreach ($luckyList as $skuMap) {
            // \Log::error($luckyList);

            if (!$skuMap['skuable']->addSales($skuMap['total'])) {
               // \Log::error('盲盒抽盒库存不足 sku_id:' . $skuMap['skuable']->id);
                ThrowException::Conflict($skuMap['skuable']->id . ' ' . $skuMap['skuable']->title . ' 盲盒库存不足，需要' . $skuMap['total'] . '库存~');
               // ThrowException::Conflict('库存不足~');
            }
        }

        return $luckyList;
    }

    // 回调
    public function packageCreatedListenerSync($order, $package)
    {
        $this->update([
            'open_index' => $this->open_index + $package->sku_total
        ]);

        $skuIndex = @$order->options['sku_index'];
        $boxRoomId = @$order->options['room_id'];
        $room = $this->rooms()->where('id', $boxRoomId)->first();
        if ($room) {
            // 标记为已打开
            $room->openSkuIndex($skuIndex);
        }

        // 如果有设置抽奖后赠送奖券，则进行赠送
        if ($this->lottery && $this->lottery->union_status === 'working' && $this->lottery->isOnStock())  {
            $total = $order->sku_total;

            $tickets = $this->lottery->sendTicketTo($order->user, $total, [
                'order' => $order
            ]);

            // 更新package的reward
            $package->updateReward([
                'lottery_ticket' => [
                    'total' => $total,
                    'title' => $this->lottery->title,
                    'id' => $this->lottery->id,
                    'uuid' => $this->lottery->uuid
                ]
            ]);
        }

        // 记录进榜单
        BoxRecord::createWith($package, $order);

        // 更新开盒统计
        Stats::updateWithPackageAndOrder($order->user, 'box', $package, $order);
    }
}
